#include "FileUtil.h"
#include <windows.h>
#include <libloaderapi.h>

#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#endif

#include "utils/stb_image.h"
#include <assert.h>
#include "../Core/CoreGlobals.h"
#include "LogUtil.h"

std::string FileUtil::sExePath;

std::string FileUtil::sAppPath;

std::string FileUtil::sRootPath;

std::string FileUtil::sAssetPath;

void FileUtil::Init()
{
	TCHAR exePath[200];
	GetModuleFileName(NULL, exePath, 200);
	sExePath = TCHAR_TO_UTF8(exePath);
	int32 index = sExePath.find_last_of('\\');
	sAppPath = sExePath.substr(0, index);
	index = sExePath.find_last_of('\\', index - 1);
	index = sExePath.find_last_of('\\', index - 1);
	sRootPath = sExePath.substr(0, index);
	sAssetPath = sRootPath + std::string("\\Assets");
}

std::string FileUtil::GetExePath()
{
	return sExePath;
}

std::string FileUtil::GetAppPath()
{
	return sAppPath;
}

std::string FileUtil::GetRootPath()
{
	return sRootPath;
}

std::string FileUtil::GetAssetPath()
{
	return sAssetPath;
}

bool FileUtil::LoadFileToArray(std::vector<uint8>& result, const std::string& filename)
{
	std::ifstream file(filename, std::ios::ate | std::ios::binary);
	if (!file.is_open()) {
		throw std::runtime_error("failed to open file!");
		return false;
	}
	size_t fileSize = (size_t)file.tellg();
	result.resize(fileSize);
	file.seekg(0);
	file.read((char*)result.data(), fileSize);
	file.close();
	return true;
}

bool FileUtil::LoadFileToString(std::string& result, const std::string& filename)
{
	std::ifstream file(filename, std::ios::in);
	if (!file.is_open()) {
		throw std::runtime_error("failed to open file!");
		return false;
	}
	std::istreambuf_iterator<char> begin(file), end;
	result.assign(begin, end);
	file.close();
	return true;
}

bool FileUtil::LoadFileToString(std::wstring& result, const std::string& filename)
{
	std::ifstream file(filename, std::ios::in);
	if (!file.is_open()) {
		throw std::runtime_error("failed to open file!");
		return false;
	}
	std::istreambuf_iterator<char> begin(file), end;
	std::string temp(begin, end);
	result = STR_TO_WSTR(temp);
	file.close();
	return true;
}

bool FileUtil::SaveArrayToFile(std::vector<uint8>& buffer, const std::string& filename)
{
	std::ofstream outfile(filename);
	if (!outfile.is_open())
	{
		throw std::runtime_error("failed to open file!");
		return false;
	}
	std::ostream_iterator<uint8> outIterator(outfile);
	std::copy(buffer.begin(), buffer.end(), outIterator);
}

bool FileUtil::DeleteFile(const std::string& filename)
{
	return std::remove(filename.c_str()) == 0;
}

void FileUtil::LoadTextureToArray(const std::string& filename, VkFormat format, std::vector<uint8>& result, uint32& width, uint32& height)
{
	assert(GStbFormat[format] <= 4);
	const std::string filePath = GetAssetPath() + std::string("\\Textures\\") + filename;


	int32 x = 0, y = 0, channels = 0;
	void* pixels = nullptr;

	if (GVkFormatSize[format] > 4)
	{
		pixels = static_cast<void*>(stbi_loadf(filePath.c_str(), &x, &y, &channels, GStbFormat[format]));
	}
	else
	{
		assert(LoadFileToArray(result, filePath));

		pixels = static_cast<void*>(stbi_load_from_memory((stbi_uc*)result.data(), result.size(), &x, &y, &channels, GStbFormat[format]));
	}

	assert(pixels != nullptr);

	width = static_cast<uint32>(x);
	height = static_cast<uint32>(y);

	result.resize(width * height * GVkFormatSize[format]);
	memcpy(result.data(), pixels, width * height * GVkFormatSize[format]);

	stbi_image_free(pixels);
}

void FileUtil::ProcessCommand(const std::string& commandStr)
{
	const int MY_PIPE_BUFFER_SIZE = 1024;

	HANDLE hPipeRead;
	HANDLE hPipeWrite;
	SECURITY_ATTRIBUTES saOutPipe;
	::ZeroMemory(&saOutPipe, sizeof(saOutPipe));
	saOutPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
	saOutPipe.lpSecurityDescriptor = NULL;
	saOutPipe.bInheritHandle = TRUE;
	if (CreatePipe(&hPipeRead, &hPipeWrite, &saOutPipe, MY_PIPE_BUFFER_SIZE))
	{
		PROCESS_INFORMATION processInfo;
		::ZeroMemory(&processInfo, sizeof(processInfo));
		STARTUPINFO startupInfo;
		::ZeroMemory(&startupInfo, sizeof(startupInfo));
		startupInfo.cb = sizeof(STARTUPINFO);
		startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
		startupInfo.hStdOutput = hPipeWrite;
		startupInfo.hStdError = hPipeWrite;
		startupInfo.wShowWindow = SW_HIDE;

		//startupInfo.dwFlags = STARTF_USESHOWWINDOW;
		//startupInfo.hStdOutput = hPipeWrite;
		//startupInfo.hStdError = hPipeWrite;
		//startupInfo.wShowWindow = SW_HIDE;
		int ret;
		//while(TRUE)

		ret = ::CreateProcess(NULL, UTF8_TO_TCHAR(commandStr.c_str()),
			NULL,  // process security
			NULL,  // thread security
			TRUE,  //inheritance
			0,     //no startup flags
			NULL,  // no special environment
			NULL,  //default startup directory
			&startupInfo,
			&processInfo);

		//::Sleep(1000);

		WaitForSingleObject(processInfo.hProcess, 3000);
		if (ret == 0)
		{
			int nRet = GetLastError();
			LOGI(L"CreateProcess last error %d", nRet);
			assert(0);
		}
		else
		{
			DWORD dwReadLen = 0;
			DWORD dwStdLen = 0;
			if (PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwReadLen, NULL) && dwReadLen > 0)
			{
				char szPipeOut[MY_PIPE_BUFFER_SIZE];
				::ZeroMemory(szPipeOut, sizeof(szPipeOut));
				if (ReadFile(hPipeRead, szPipeOut, dwReadLen, &dwStdLen, NULL))
				{
					LOGI(L"Output %s", UTF8_TO_TCHAR(szPipeOut));
				}
			}

		}
		if (processInfo.hProcess)
		{
			CloseHandle(processInfo.hProcess);
		}
		if (processInfo.hThread)
		{
			CloseHandle(processInfo.hThread);
		}
	}
	CloseHandle(hPipeRead);
	CloseHandle(hPipeWrite);
}

